/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package universityModel.utils;

import java.util.Arrays;

/**
 * Resizable-array implementation of the <tt>MiniList</tt> interface.
 * Forbid null elements.  In addition to implementing the <tt>MiniList</tt> interface,
 * this class provides methods to manipulate the size of the array that is
 * used internally to store the list. This class is unsynchronized, so
 * you must care about synchronization if you work with multiple threads.
 *
 * @author good programist!
 */
public class ArrayModel<E> implements AdvancedArray<E> {
    /**
     * The array buffer into which the elements of the MiniArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private Object[] data;

    /**
     * The number of elements in this MiniArrayList.
     */
    private int size;

    /**
     * Constructs an empty array with the specified initial capacity.
     *
     * @param initialCapacity the initial capacity of the buffer
     * @throws IllegalArgumentException if the specified initial capacity
     *                                  is negative
     */
    public ArrayModel(ArrayModel<E> arrayModel) {
        size = arrayModel.size();
        this.data = arrayModel.getData(); 
    }

    public Object[] getData() {
        return data.clone();
    }
  
    public ArrayModel(int initialCapacity) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: " +
                    initialCapacity);
        this.data = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayModel() {
        this(10);
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Increases the capacity of this <tt>MiniArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        if (minCapacity > 0)
            ensureCapacityInternal(minCapacity);
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (minCapacity > data.length)
            grow(minCapacity);
    }

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        int oldCapacity = data.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        if (newCapacity < minCapacity) {
            newCapacity = minCapacity;
        }
        if (newCapacity < 0) {
            throw new OutOfMemoryError();
        }
        data = Arrays.copyOf(data, newCapacity);
    }

    @Override
    public Object[] toArray() {
        return Arrays.copyOf(data, size);
    }

    @SuppressWarnings("unchecked")
	private E data(int index) {
        return (E) data[index];
    }

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt>
     * @throws NullPointerException if the specified element is null and this
     *                              list does not permit null elements
     */
    @Override
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        if (e == null) {
            throw new NullPointerException("Null elements are not allowed");
        }
        data[size++] = e;
        return true;
    }

    /**
     * Returns the element at the specified position in this list.
     *
     * @param index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException if the index is out of range
     *                                   (<tt>index &lt; 0 || index &gt;= size()</tt>)
     */
    @Override
    public E get(int index) {
        rangeCheck(index);
        return data(index);
    }
    
    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left.
     * Returns the element that was removed from the
     * list.
     *
     * @param index the index of the element to be removed
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException if the index is out of range
     *                                   (<tt>index &lt; 0 || index &gt;= size()</tt>)
     */
    @Override
    public E remove(int index) {
        rangeCheck(index);

        E removedValue = data(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(data, index + 1, data, index, numMoved);
        data[--size] = null;

        return removedValue;
    }

    /**
     * Removes all of the elements from this list.
     * The list will be empty after this call returns.
     */
    @Override
    public void clear() {
        for (int i = 0; i < size; i++) {
            data[i] = null;
        }
        size = 0;
    }

    @Override
    public void sort() {
        Arrays.sort(data);
    }
    
    private void rangeCheck(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size());
        }
    }
}
